package com.atguigu.tingshu.user.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.common.constant.RabbitConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {
        // 根据用户id计算该用户的播放进度应该存放的集合
        Long userId = AuthContextHolder.getUserId();
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess process = mongoTemplate.findOne(Query.query(
                        Criteria.where("userId").is(userId).and("trackId").is(trackId)),
                UserListenProcess.class, collectionName);
        if (process != null) {
            return process.getBreakSecond();
        }
        return new BigDecimal("0");
    }

    @Override
    public void updateListenProcess(UserListenProcessVo vo) {
        Long userId = AuthContextHolder.getUserId();
        // 如果当前为登录，则不记录播放进度信息
        if (userId == null) return;
        // 根据用户id和声音id，查询已保存的播放信息
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        Long trackId = vo.getTrackId();
        UserListenProcess process = mongoTemplate.findOne(
                Query.query(Criteria.where("userId").is(userId).and("trackId").is(trackId)),
                UserListenProcess.class, collectionName);
        if (process == null) {
            // 新增播放进度到MongoDB
            process = new UserListenProcess();
            process.setId(ObjectId.get().toString());
            process.setUserId(userId);
            BeanUtils.copyProperties(vo, process);
            process.setCreateTime(new Date());
            process.setUpdateTime(new Date());
            process.setIsShow(1);
            mongoTemplate.insert(process, collectionName);
        } else {
            // 修改更新时间与进度时间
            mongoTemplate.updateFirst(
                    Query.query(Criteria.where("_id").is(process.getId())),
                    new Update().set("createTime", new Date()).set("updateTime", new Date()),
                    UserListenProcess.class
            );
        }
        /*
            从redis的bitmap中查询该用户当天是否第一次播放该专辑
            bitmap：位图    getBit(key, offset)
                key：Redis中的键，表示位图所在的位置。
                offset: 位图中的偏移量，即要设置的位的位置。偏移量从0开始，表示位图的第一个位。
         */
        String key = "user:track:" + DateUtil.today() + ":" + userId;
        Boolean bit = redisTemplate.opsForValue().getBit(key, trackId);
        if (!bit) {
            // 该用户当天是第一次播放该专辑，更新bitmap后发送消息修改专辑和声音的播放量
            redisTemplate.opsForValue().setBit(key, trackId, true);
            // 设置过期时间：只需要记录到凌晨时间即可，这里计算过期时间 = 明天凌晨 - 当前时间
            LocalDateTime nextDay = LocalDateTime.of(LocalDate.now().plusDays(1), LocalTime.MIN);
            long expireTime = ChronoUnit.SECONDS.between(LocalDateTime.now(), nextDay);
            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
            // 组装消息
            TrackStatMqVo statMqVo = new TrackStatMqVo();
            // 防止重复消费的唯一标识
            statMqVo.setBusinessNo(IdWorker.getIdStr());
            BeanUtils.copyProperties(vo, statMqVo);
            statMqVo.setStatType(SystemConstant.TRACK_STAT_PLAY);
            statMqVo.setCount(1);
            // 发送消息
            rabbitTemplate.convertAndSend(RabbitConstant.STAT_UPDATE_QUEUE, JSON.toJSONString(statMqVo));
        }
    }

    @Override
    public Map<String, Long> getLatelyTrack() {
        Map<String, Long> resultMap = new HashMap<>();
        Long userId = AuthContextHolder.getUserId();
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess process = mongoTemplate.findOne(Query.query(Criteria.where("userId").is(userId))
                        .with(Sort.by(Sort.Direction.DESC, "updateTime")),
                UserListenProcess.class,
                collectionName);
        if (process != null) {
            resultMap.put("albumId", process.getAlbumId());
            resultMap.put("trackId", process.getTrackId());
        }
        return resultMap;
    }
}
